from database.park_location_record_table import ParkLocationRecordTable
from manager.lock_manager import LockManager
from model.park_spider import ParkSpider
from model.park_platform import ParkPlatform
from model.car_number import CarNumber
from model.result import Result
from model.error import ParkSpiderError, ParkSpiderErrorCode, TokenExpireError

from urllib import parse
import common.http as http
import spider_config
import time
from common.logger import logger
import dateutil.parser as dateutil

req_interval = 0.3


class YunParkSpider(ParkSpider):
    def __init__(self) -> None:
        self.__carNumber = None
        self.__carId = None

    def platform(self) -> ParkPlatform:
        return ParkPlatform(spider_config.yun_park_id)

    def setCarNumber(self, carNumber):
        self.__carNumber = carNumber

    def getHeaders(self):
        return {
            "Content-Type": "application/x-www-form-urlencoded",
        }

    def getBindInfos(self):
        account = self.getAccount()

        data = {
            "uin": account["uin"],
            "appid": account["appid"],
            "token": account["token"],
        }
        data = parse.urlencode(data)

        for i in range(3):
            time.sleep(req_interval)

            rsp = http.post(
                "http://yun.bolink.club/official/getcarnumbers",
                headers=self.getHeaders(),
                data=data,
                proxies=self.getProxy(),
                timeout=self.getTimeout(),
            )

            if rsp.text == "-8":
                logger.debug(f"智慧停车云获取绑定车辆异常:{account}")
                continue
            try:
                return rsp.json()
            except Exception as e:
                logger.error(repr(e))
        raise TokenExpireError(account["uin"])

    def bind(self):
        infos = self.getBindInfos()

        self.__carId = None

        if infos:
            for i in infos:
                if "car_number" not in i:
                    logger.error(f"智慧停车云 {self.__carNumber} 获取绑定车辆错误：{infos}")
                    continue
                if i["car_number"] == str(self.__carNumber):
                    self.__carId = i["id"]
                    break

        if self.__carId:
            return True

        if infos and len(infos) >= 20:
            self.unbind(infos[0]["id"])

        account = self.getAccount()

        data = {
            "openid": "",
            "uin": account["uin"],
            "appid": account["appid"],
            "carnumber": str(self.__carNumber),
            "token": account["token"],
        }

        data = parse.urlencode(data)

        repeat = 0

        while True:
            time.sleep(req_interval)

            rsp = http.post(
                "http://yun.bolink.club/official/editcarnumber",
                headers=self.getHeaders(),
                data=data,
                proxies=self.getProxy(),
                timeout=self.getTimeout(),
            )

            logger.debug(f"智慧停车云绑定车辆结果:{rsp.text}")

            if rsp.text == "":
                # 操作太快
                logger.debug(f"操作太快,重试")
                repeat += 1
                if repeat >= 3:
                    return False
                continue

            break

        if rsp.text == "-8":
            # 异常车辆
            logger.debug(f"智慧停车云绑定车辆 {self.__carNumber} 异常:{rsp.text}")
            return False

        infos = self.getBindInfos()

        if not infos:
            # logger.warning(f"智慧停车云绑定车辆 {self.__carNumber} 异常:{rsp.text}")
            return False

        for i in infos:
            if "car_number" not in i:
                logger.error(f"智慧停车云 {self.__carNumber} 获取绑定车辆错误：{infos}")
                continue
            if i["car_number"] == str(self.__carNumber):
                self.__carId = i["id"]
                break

        return self.__carId is not None

    def unbind(self, carId: str):
        account = self.getAccount()

        data = {
            "car_id": carId,
            "uin": account["uin"],
            "car_number": str(self.__carNumber),
            "token": account["token"],
        }

        data = parse.urlencode(data)

        time.sleep(req_interval)

        rsp = http.post(
            "http://yun.bolink.club/official/delcarnumber",
            headers=self.getHeaders(),
            data=data,
            proxies=self.getProxy(),
            timeout=self.getTimeout(),
        )

        logger.debug(f"智慧停车云解绑车辆结果:{rsp.text}")

        # if rsp.text != "1":
        #     logger.warning(f"智慧停车云解绑车辆异常:{rsp.text}")

        return True

    def query(self, carNumber: CarNumber) -> Result:
        self.setCarNumber(carNumber)

        account = self.getAccount()

        if not account:
            raise ParkSpiderError(ParkSpiderErrorCode.YunAccountEmpty)

        with LockManager.instance().get(self.platform().id, account["uin"]):
            # try:
            result = Result()
            result.platform = self.platform()
            result.car_number = carNumber

            data = {
                "openid": "",
                "uin": account["uin"],
                "appid": account["appid"],
                "car_number": str(carNumber),
                "token": account["token"],
            }

            data = parse.urlencode(data)

            # with LockManager.instance().get(self.platform().id, account["uin"]):
            if not self.bind():
                # logger.warning(f"智慧停车云绑定车辆 {carNumber} 失败")
                return result

            time.sleep(req_interval)

            rsp = http.post(
                "http://yun.bolink.club/official/getwxcurorderlist",
                headers=self.getHeaders(),
                data=data,
                proxies=self.getProxy(),
                timeout=self.getTimeout(),
            )

            self.unbind(self.__carId)

            # finally:
            #     lock.release()

            # logger.info(f"智慧停车云查询 {carNumber} 结果:{rsp.text}")

            if rsp.status_code != 200:
                result.error_code = rsp.status_code
                result.message = rsp.text
                return result

            try:
                rspJson = rsp.json()

                if not rspJson:
                    return result

                info = rspJson[0]
                result.success = True
                result.enter_time = dateutil.parse(info["in_park_time"])
                result.park_name = info["park_name"]

                try:
                    with ParkLocationRecordTable(spider_config.yima_park_id) as db:
                        record = db.query(info["com_id"], result.park_name)
                        if record:
                            result.park_name = record
                            logger.info(f"匹配到parkid:{record}")
                        else:
                            logger.info(f"未匹配到parkid:{info}")
                    result.price = float(info["total"])
                except:
                    pass

            except Exception as e:
                logger.error(repr(e))
                result.success = False
                result.message = repr(e)
                
            return result
